module ecs {
    /**
     * 包含您的世界的配置。
     * 
     * 可用于:
     * - 添加系统
     * - 增加管理器
     * - 注册Pojo注入
     * - 注册自定义依赖注入器
     */
    export class WorldConfiguration{
        public static COMPONENT_MANAGER_IDX: number = 0;
        public static ENTITY_MANAGER_IDX: number = 1;
        public static ASPECT_SUBSCRIPTION_MANAGER_IDX: number = 2;
        
        public systems: Bag<BaseSystem> = new Bag<BaseSystem>();
        
        private _expectedEntityCount: number = 128;
        public injectables: {[s: string]: Object} = {};
        public invocationStrategy: SystemInvocationStrategy;
        public injector: Injector;
        private _alwaysDelayComponentRemoval: boolean = false;
        private _registered: BaseSystem[] = [];

        constructor(){
            // 为核心管理器保留空间
            this.systems.add(null); // ComponentManager
            this.systems.add(null); // EntityManager
            this.systems.add(null); // AspectSubscriptionManager
        }

        public expectedEntityCount(){
            return this._expectedEntityCount;
        }

        public setSystem<T extends BaseSystem>(system: T){
            this.systems.add(system);

            if (!this._registered.push(system)){
                let name = egret.getQualifiedSuperclassName(system);
                throw new Error(name + "already added to" + egret.getQualifiedSuperclassName(this));
            }

            return this;
        }

        /**
         * 设置注入器来处理所有依赖注入
         * @param injector 
         */
        public setInjector(injector: Injector): WorldConfiguration{
            if (!injector)
                throw new Error("Injector must not be null");

            this.injector = injector;
            return this;
        }

        public setInvocationStrategy(invocationStrategy: SystemInvocationStrategy){
            if (invocationStrategy == null) throw new Error("null pointer");
            this.invocationStrategy = invocationStrategy;
            return this;
        }

        /**
         * 延迟组件删除，直到通知所有订阅。
         */
        public isAlwaysDelayComponentRemoval(){
            return this._alwaysDelayComponentRemoval;
        }

        /**
         * 延迟组件删除，直到通知所有订阅
         * @param value 为true 所有组件的组件移除将被延迟。
         */
        public setAlwaysDelayComponentRemoval(value: boolean){
            this._alwaysDelayComponentRemoval = value;
        }

        public initialize(world: World, injector: Injector, asm: AspectSubscriptionManager){
            if (!this.invocationStrategy)
                this.invocationStrategy = new InvocationStrategy();
            
            this.invocationStrategy.setWorld(world);

            world.invocationStrategy = this.invocationStrategy;

            this.systems.set(WorldConfiguration.COMPONENT_MANAGER_IDX, world.getComponentManager());
            this.systems.set(WorldConfiguration.ENTITY_MANAGER_IDX, world.getEntityManager());
            this.systems.set(WorldConfiguration.ASPECT_SUBSCRIPTION_MANAGER_IDX, asm);

            for (let i = 0; i < this.systems.size(); i ++){
                let system = this.systems.get(i) as BaseSystem;
                if (system){
                    world.partition.systems.add(egret.getQualifiedSuperclassName(system), system);
                    system.setWorld(world);
                }

                if (system instanceof Manager){
                    (system as Manager).registerManager();
                }
            }

            injector.initialize(world, this.injectables);
            this.initializeSystems(injector);

            this.invocationStrategy.setSystems(this.systems);
            this.invocationStrategy.initialize();
        }

        private initializeSystems(injector: Injector){
            for (let i = 0, s = this.systems.size(); i < s;i++){
                let system = this.systems.get(i);
                injector.inject(system);
            }

            for (let i = 0, s = this.systems.size(); i < s; i ++){
                let system = this.systems.get(i);
                system.initialize();
            }
        }
    }
}
